﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Tomahawk.Runtime.Logic;
using Tomahawk.Runtime.Physics.Interfaces;
using Tomahawk.Runtime.Serialization;


namespace Tomahawk.Runtime.Physics.Descriptors
{
    #region Materials
    public enum MaterialID
    {
        Unset, 
        UserDefined, 
        NotBouncySmooth, 
        NotBouncyNormal, 
        NotBouncyRough,
        NormalSmooth, 
        NormalNormal, 
        NormalRough,
        BouncySmooth, 
        BouncyNormal, 
        BouncyRough,
        NumMaterialTypes
    }
    #endregion

    #region Shape Descriptors
    [XmlInclude(typeof(PhysicsSphereShapeDesc))]
    [XmlInclude(typeof(PhysicsBoxShapeDesc))]
    [XmlInclude(typeof(PhysicsCapsuleShapeDesc))]
    [XmlInclude(typeof(PhysicsPlaneShapeDesc))]
    [XmlInclude(typeof(PhysicsMeshShapeDesc))]
    public abstract class PhysicsShapeDesc
    {
        // Transform
        public Vector3 localTransform = Vector3.Zero;
        public Quaternion localRotation = Quaternion.Identity;

        // Material
        public MaterialID materialID = MaterialID.UserDefined;
        public float elasticity = 0.5f;
        public float staticRoughness = 0.7f;
        public float dynamicRoughness = 0.6f;
    }

    // Sphere
    public sealed class PhysicsSphereShapeDesc : PhysicsShapeDesc
    {
        public float radius = 1.0f;
    }

    // Box
    public sealed class PhysicsBoxShapeDesc : PhysicsShapeDesc
    {
        public Vector3 Extents = new Vector3(1.0f, 1.0f, 1.0f);
    }

    // Capsule
    public sealed class PhysicsCapsuleShapeDesc : PhysicsShapeDesc
    {
        public float radius = 1.0f;
        public float height = 1.0f;
    }

    // Plane
    public sealed class PhysicsPlaneShapeDesc : PhysicsShapeDesc
    {
        public Vector3 up = Vector3.Up;
        public float d = 0.0f;
    }

    // Mesh
    public sealed class PhysicsMeshShapeDesc : PhysicsShapeDesc
    {
        public List<Vector3> vertexList = new List<Vector3>();
        public List<Vector3> indexList = new List<Vector3>();

        public void LoadFromModel(Model model)
        {
            vertexList = new List<Vector3>();
            indexList = new List<Vector3>();
            Tomahawk.Runtime.Utils.MeshUtils.ExtractData(vertexList, indexList, model);
        }
    }

    #endregion

    #region Body Descriptors
    public sealed class PhysicsBodyDesc
    {
        public float mass = 1.0f;
        public SerializableList<PhysicsShapeDesc> shapes = new SerializableList<PhysicsShapeDesc>();
    }
    #endregion

    #region Constraint Descriptors
    public class PhysicsConstraintDesc
    {
        public string body1;
        public string body2;
    }
    #endregion

    #region Actor Descriptors

    public enum PhysicsActorType
    {
        StaticActor = 0,     // The actor is considered static, so no update is needed
        InterpActor = 1,     // The actor movement is controlled by the game logic. The physics actor position is updated from the logic actor position
        DynamicActor = 2,     // The actor movement is controlled by the game physics. The logic actor position is updated from the physics actor position
        TriggerActor = 3,     // The actor can't be collided. It will generate events to notify other actors when they touch or untouch the trigger
    }

    public sealed class PhysicsActorDesc
    {
        public string name;
        public PhysicsActorType type;
        public SerializableDictionary<string, PhysicsBodyDesc> bodies = new SerializableDictionary<string, PhysicsBodyDesc>();        
        public SerializableList<PhysicsConstraintDesc> constraints = new SerializableList<PhysicsConstraintDesc>();
    }
    #endregion
}
